<?php

declare (strict_types = 1);

namespace app\common\service;

use app\common\exception\AdminException;
// 导入对应产品模块的client
use TencentCloud\Sms\V20210111\SmsClient;
// 导入要请求接口对应的Request类
use TencentCloud\Sms\V20210111\Models\SendSmsRequest;
use TencentCloud\Common\Exception\TencentCloudSDKException;
use TencentCloud\Common\Credential;
// 导入可选配置类
use TencentCloud\Common\Profile\ClientProfile;
use TencentCloud\Common\Profile\HttpProfile;
use think\facade\Log;

class SmsService
{
    private $client;
    private $config;

    public function __construct()
    {
        $this->config = get_config('sms_config');
        $this->initClient();
    }

    /**
     * 初始化短信客户端
     *
     * @return void
     */
    private function initClient(): void
    {
        try {
            $cred = new Credential(
                $this->config['secret_id'],
                $this->config['secret_key']
            );

            $httpProfile = new HttpProfile();
            $httpProfile->setReqTimeout($this->config['http_timeout']);

            $clientProfile = new ClientProfile();
            $clientProfile->setHttpProfile($httpProfile);

            $this->client = new SmsClient(
                $cred,
                $this->config['region'],
                $clientProfile
            );
        } catch (\Throwable $e) {
            $this->logError('Client init failed', $e);
            throw new AdminException('短信服务初始化失败', 500);
        }
    }

    /**
     * 发送短信
     * @param array|string $phoneNumbers 手机号（支持数组批量发送）
     * @param array $templateParams 模板参数
     * @param string|null $templateId 模板ID（可选）
     * @param string|null $signName 签名（可选）
     * @return array|string
     */
    // 模板内容："验证码：{1}，有效期{2}分钟"
    //    $$templateParams = [
    //    "X8H9P",  // 验证码
    //    "10"      // 有效期（数字也要转字符串！）
    //    ];
    public function send(array|string $phoneNumbers, array $templateParams = [],
                         string $templateId = null, string $signName = null): array|string
    {
        try {
            $req = new SendSmsRequest();

            // 参数处理
            $phones = is_array($phoneNumbers) ? $phoneNumbers : [$phoneNumbers];
            $req->PhoneNumberSet = array_map(function($phone) {
                return $this->formatPhoneNumber($phone);
            }, $phones);

            $req->SmsSdkAppId = $this->config['sdk_app_id'];
            $req->SignName = $signName ?? $this->config['sign_name'];
            $req->TemplateId = $templateId ?? $this->config['template_id'];
            $req->TemplateParamSet = $templateParams;

            $response = $this->client->SendSms($req);
            $result = json_decode($response->toJsonString(), true);

            // 记录日志
            $this->logInfo('短信发送结果', $result);

            // 处理结果
            if ($result['SendStatusSet'][0]['Code'] !== 'Ok') {
                throw new AdminException($result['SendStatusSet'][0]['Message'], 500);
            }

            return $result;

        } catch (\Throwable $e) {
            $this->logError('短信发送失败', $e);
            throw new AdminException('短信发送失败: ' . $e->getMessage(), 500);
        }
    }

    // 格式化手机号（自动添加国际区号）
    private function formatPhoneNumber(string $phone): string
    {
        if (str_starts_with($phone, '+')) {
            return $phone;
        }
        return '+86' . ltrim($phone, '0');
    }

    /**
     * 记录日志
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    private function logInfo(string $message, array $context = []): void
    {
        if ($this->config['enable_log']) {
            Log::info($message, $context);
        }
    }

    /**
     * 错误日志
     *
     * @param string $message
     * @param \Throwable $e
     * @return void
     */
    private function logError(string $message, \Throwable $e): void
    {
        if ($this->config['enable_log']) {
            Log::error($message, [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }
}